package it.gestionedocumentale.hibernate.dao;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;

import it.gestionedocumentale.model.Documento;
import it.gestionedocumentale.model.Utente;
import it.gestionedocumentale.struts.form.RicercaDocumentoForm;


public class DocumentoDAO extends BaseHibernateDAO {

	
	// property constants
	public static final String NOME_DOCUMENTO = "nomeDocumento";
	public static final String PATH = "path";
	public static final String SIZE = "size";
	public static final String DATA_UPLOAD = "dataUpload";
	
	
	public void save(Documento transientInstance) throws Exception{
		getSession().save(transientInstance);
	}
	
	public void update(Documento transientInstance) throws Exception{
		getSession().saveOrUpdate(transientInstance);
	}
	
	public void delete(Documento persistentInstance) throws Exception{
		getSession().delete(persistentInstance);
	}
	
	public Documento findById(Long id) throws Exception{
		Documento instance = (Documento) getSession().get(Documento.class, id);
		return instance;
	}
	
	@SuppressWarnings("unchecked")
	public List<Documento> findByExample(Documento instance) {
		Criteria cri = getSession().createCriteria(Documento.class);
		cri.add(Example.create(instance));
		if (instance.getUtenteCreatore() != null) {
			cri.add(Restrictions.eq("utenteCreatore", instance.getUtenteCreatore()));
		}
		List<Documento> results = cri.list();
		return results;
	}
		
	@SuppressWarnings("unchecked")
	public List<Documento> findAll() throws Exception{
		String queryString = "from Documento";
		Query queryObject = getSession().createQuery(queryString);
		return queryObject.list();
	}

	@SuppressWarnings("unchecked")
	public List<Documento> findByProperty(String propertyName, Object value) throws Exception{
		String queryString = "from Documento as model where model." + propertyName
				+ "= ?";
		Query queryObject = getSession().createQuery(queryString);
		queryObject.setParameter(0, value);
		return queryObject.list();
	}
	
	public List<Documento> findByNomeDocumento(Object nomeDocumento) throws Exception{
		return findByProperty(NOME_DOCUMENTO, nomeDocumento);
	}
	
	public List<Documento> findByPath(Object path) throws Exception{
		return findByProperty(PATH, path);
	}
	
	public List<Documento> findBySize(Object size) throws Exception{
		return findByProperty(SIZE, size);
	}
		
	public List<Documento> findByDataUpload(Object dataUpload) throws Exception{
		return findByProperty(DATA_UPLOAD, dataUpload);
	}
	
	public Documento merge(Documento detachedInstance) throws Exception{
		Documento result = (Documento) getSession().merge(detachedInstance);
		return result;
	}
	
	//il metodo torna un Set di Documenti contententi la stringa cercata in doc.nomeDocumento,
	//doc.tag.descrizione e doc.classificazione.descrizione
	@SuppressWarnings("unchecked")
	private Set<Documento> simpleSearchByString(String stringaDiRicerca) {
		Criteria cri = getSession().createCriteria(Documento.class);
		cri.add(Restrictions.ilike(NOME_DOCUMENTO, stringaDiRicerca, MatchMode.ANYWHERE));
		Set<Documento> results = new HashSet<Documento>(cri.list());
		Criteria cri2 = getSession().createCriteria(Documento.class);
		cri2.createAlias("listaClassificazioni", "classificazione");
		cri2.add(Restrictions.ilike("classificazione.descrizione", stringaDiRicerca, MatchMode.ANYWHERE));
		results.addAll(cri2.list());
		Criteria cri3 = getSession().createCriteria(Documento.class);
		cri3.createAlias("listaTag", "tag");
		cri3.add(Restrictions.ilike("tag.descrizione", stringaDiRicerca, MatchMode.ANYWHERE));
		results.addAll(cri3.list());
		return results;
	}
	
	/*	il metodo cerca tutti i documenti visibili all'utente 
	*	e al suo gruppo e fa l'intersezione
	*	tra questi e quelli che risultano dal metodo simpleSearchByString
	*/	
	@SuppressWarnings("unchecked")
	public Set<Documento> simpleSearch(Utente utente, String stringaDiRicerca) {
		Criteria cri = getSession().createCriteria(Documento.class);
		cri.createAlias("listaUtenti", "utente");
		cri.add(Restrictions.eq("utente.idUtente", utente.getIdUtente()));
		Set<Documento> results = new HashSet<Documento>(cri.list());
		Criteria cri2 = getSession().createCriteria(Documento.class);
		cri2.createAlias("listaGruppi", "gruppo");
		cri2.add(Restrictions.eq("gruppo.idGruppo", utente.getGruppo().getIdGruppo()));
		results.addAll(cri2.list());
		if (stringaDiRicerca!=null && !(stringaDiRicerca.equals(""))) {
			Set<Documento> documentiConStringa = simpleSearchByString(stringaDiRicerca);
			results.retainAll(documentiConStringa);
		}
		return results;
	}
	
	@SuppressWarnings("unchecked")
	private Set<Documento> advancedSearchByExample(RicercaDocumentoForm form) throws Exception {
		Criteria cri = getSession().createCriteria(Documento.class);
		if(form.getNomeDocumento()!=null) {
			cri.add(Restrictions.ilike(NOME_DOCUMENTO, form.getNomeDocumento(), MatchMode.ANYWHERE));
		}
		if(form.getDataInizio()!=null || form.getDataFine()!=null) {
			cri.add(Restrictions.between(DATA_UPLOAD, form.getDataInizio(), form.getDataFine()));
		}
		if(form.getIdClassificazione()!=null) {
			cri.createAlias("listaClassificazioni", "classificazione");
			cri.add(Restrictions.eq("classificazione.idClassificazione", form.getIdClassificazione()));
		}
		if(form.getIdTag()!=null) {
			cri.createAlias("listaTag", "tag");
			cri.add(Restrictions.eq("tag.idTag", form.getIdTag()));
		}
		Set<Documento> results = new HashSet<Documento>(cri.list());
		return results;
	}
	
	@SuppressWarnings("unchecked")
	public Set<Documento> advancedSearch(Utente utente, RicercaDocumentoForm form) throws Exception {
		Criteria cri = getSession().createCriteria(Documento.class);
		cri.createAlias("listaUtenti", "utente");
		cri.add(Restrictions.eq("utente.idUtente", utente.getIdUtente()));
		Set<Documento> results = new HashSet<Documento>(cri.list());
		Criteria cri2 = getSession().createCriteria(Documento.class);
		cri2.createAlias("listaGruppi", "gruppo");
		cri2.add(Restrictions.eq("gruppo.idGruppo", utente.getGruppo().getIdGruppo()));
		results.addAll(cri2.list());
		results.retainAll(advancedSearchByExample(form));
		return results;
	}
	
}
